namespace Chapter2
    (*
  General discussion ( * )

  We will now explain in depth the various constructs we have seen in action in the sample above.
  We start by showing how to define simple records to classify and organize our data.
  We will show how we can augment our record definition with operations on the record fields.
  We will also show how we can create generic records which take as input a type that they use for their fields.
  We will then show how units of measure work and how they may be used to build mini-languages inside F#.
  *)
  module Examples =

    (*
    Records  ( * ):

    Suppose we have a complex data structure such as a rocket.
    All the data about the rocket is a series of floating point numbers:
    - x
    - y
    - vx
    - vy
    - base mass
    - stage1 fuel
    - ...

    if we used tuples to represent our rocket, we would end up with something very confusing, like:
    float * float * float * float * float ... * float

    We would get no compiler error for a mistake like writing
    (vx,vy, x, y, ... )

    instead of
    (x,y,vx,vy, ...)

    that is all the fields are the same from the point of view of the compiler and if by mistake we swap some fields then the compiler is ok with it but the program will not work.

    Records are precisely a solution to this problem: a record is a tuple (possibly very long) where each field has a specific name.
    A record is defined as follows:
    type RECORD_NAME = { Field1Name : Field1Type; Field2Name : Field2Type; ... FieldnName : FieldnType }

    An example record is the Person:
    *)

    type Person = { Name : string; Surname : string; Age : int }

    (*
    We can create a value of record type by writing:
    { Field1Name = v1; Field2Name = v2; ... FieldnName = vn }

    where of course v1, v2, ..., vn all have the right type for the i-th field.

    We can create a value of type Peson by writing:
    *)

    let john_doe = { Name = "John"; Surname = "Doe"; Age = 37 }

    (*
    We can read a field from a record with the dot ( . ) operator. The returned value has the type of the field:
    *)

    let name = john_doe.Name

    (*
    Type inference works wuite well with records. For example, suppose we have the function that extracts the full name of a person.
    Just by the usage of the Name and Surname fields the type inference algorithm infers that x has type Person:
    *)

    let fullname x = x.Name + ", " + x.Surname

    (*
    Records may be constructed as copies of other records by specifiying only those fields which must be changed.
    We write
    { x with FieldiName = vi; ... FieldjName = vj }

    where x is a record of type Record. The result will be a record where all the fields have the same value of the same fields in x apart from the fields which have been specified after the "with" keyword.

    We can create a Jane Doe from our John Doe by writing:
    *)

    let jane_doe = { john_doe with Name = "Jane" }

    (*
    Record serialization ( ** )

    For those who often use serialization, it is important to notice that records do not have a parameterless constructor, and as such they do not work inside serializers that require one.
    Presumably this is a bad design decision on the part of the serializer developers, whou should never request such a potentially dangerous feature such as a parameterless constructor just for serializing.

    In practice this means that F# records will work with serializers such as BinarySerializer and not XmlSerializer.
    *)

    (*
    Members ( * )

    Records can have member functions. Member functions are functions that are associated with a record value, and which can be invoked as if they were fields of the record itself.
    Member functions are used to augment the record with some basic capabilities for manipulating itself.

    We add a member fcunction to a record with the:
    member SELF-NAME.FUNCTION-NAME = BODY

    where SELF-NAME is the name of the record instance on which the function has been called.

    For example, let us say we have a record Employee which holds a person and a job, and we wish to be able to change the job at will; then the Employee record will have a ChangeJob member:
    *)

    type Employee =
      {
        Person : Person
        Job    : string
      }
      member self.ChangeJob new_job = { self with Job = new_job }

    (*
    Members may also be parameterless; in that case they act exactly as fields, but do not worry: their computations are not performed until they are used.
    *)

    type Department =
      {
        Boss         : Person
        NumEmployees : int
        Name         : string
      }
      member this.Description = "Department " + this.Name + " is managed by " + this.Boss.Name

    (*
    Memmbers do not necessarily have to be associated with an instance. For example, a member may be simply a function associated with a record type. In that case the member function is said to be static, and it is declared with the "static" keyword:
    *)

    type Job =
      {
        Department    : string
        HoursPerWeek  : int
        SalaryPerWeek : int
      }
      member job.Sucks = job.SalaryPerWeek / job.HoursPerWeek < 4
      static member CreateDefaultJob() = { Department = "Accounting"; HoursPerWeek = 40; SalaryPerWeek = 400 }

    (*
    A record may contain mutable fields. Mutable fields in a record are fields which can be changed, and are either marked with the "mutable" modifier or have type Ref<T> for some type T.
    *)

    type Traveler =
      {
        Person           : Person
        mutable Location : string
        CurrentActivity  : Ref<string>
      }

    let john_traveler = { Person = john_doe; Location = "Cambodia"; CurrentActivity = ref "Fishing" }
    do john_traveler.Location <- "California"
    do john_traveler.CurrentActivity := "Surfing"

    (*
    Generic records ( ** )

    Records may have a generic type.
    Having a generic type is useful if you wish to construct records with fields that have a certain name and shape, but which can be instanced to any possible type.
    We write:
    type RECORD-NAME<RECORD-TYPE-PARAMS> = ...

    where RECORD-TYPE-PARAMS is a tuple of type parameters such as 'a, 'b, 'c, ...
    A generic record can be thought of as a function that takes as input one or more types (called 'a, 'b, etc. inside the record definition) and which returns as output a type (the type of the record with the parameters instantiated).
    Let us start with a very simple generic record which models a pair:
    *)
    type Pair<'a,'b> = { First : 'a; Second : 'b }

    let my_pair : Pair<int,string> = { First = 10; Second = "hello" }

    (*
    Notice that the type annotation for my_pair is not needed, and it is provided only for illustrative purposes.

    Now we can use the Pair type for any types of values we wish to put inside it, and we will not have to redefine the pair for integers and strings, integers and floats, etc.
    Of course, we could even define a value of a type which uses Pair inside Pair itself:
    *)

    let my_pair' = { First = { First = 10; Second = 5.0 }; Second = { First = System.DateTime.Now; Second = "hello" } }

    (*
    Type inference comes quite useuful in this case because the type of my_pair' would be quite long and bothersome to write.
    *)

    (*
    This feature is particularly useful when we wish to represent operations with records of generic functions.
    For example, consider the set of operations that characterize a generic number of type 'a:
    *)

    type Number<'a> = { Zero : 'a; One : 'a; Sum : 'a -> 'a -> 'a; Mul : 'a -> 'a -> 'a; Neg : 'a -> 'a }

    (*
    Any function that manipulates generic numbers will now take as input an additional parameter (usually the first, so that we can take advantage of partial specialization to make it disappear, see Chapter 1) of type Number<'a>:
    *)

    let line num q m x =
      let ( + ) = num.Sum
      let ( * ) = num.Mul
      q + m * x

    let float_num = { Zero = 0.0; One = 1.0; Sum = ( + ); Mul = ( * ); Neg = ( ~- ) }
    let int_num = { Zero = 0; One = 1; Sum = ( + ); Mul = ( * ); Neg = ( ~- ) }

    let float_line = line float_num
    let int_line = line int_num

    let line_3x2 = int_line 2 3
    let line_4x2 = float_line 2.0 4.0

    (*
    We can even define a generic number record for complex numbers:
    *)

    let complex_num num =
      let ( + ) = num.Sum
      let ( * ) = num.Mul
      let ( ~- ) = num.Neg
      {
        Zero = (num.Zero,num.Zero)
        One  = (num.One,num.Zero)
        Sum  = fun (a,b) (c,d) -> (a+c,b+d)
        Mul  = fun (a,b) (c,d) -> (a*c + (-(b*d)), b*c + a*d)
        Neg  = fun (a,b) -> (-a,-b)
      }

    (*
    The type of complex_num is Number<'a> -> Numbre<'a * 'a>, that is complex_num converts a number definition for numbers of type 'a into an equivalent definition for pairs 'a * 'a.

    This style of programming is very powerful, since it is very similar to the use of interfaces in object-oriented programming but with the important advantage that we can easily represent static operations such as getting the zero or sum and multiplication.
    *)

    (*
    Units of Measure ( * )

    A particular kind of generic types is called units of measure.
    Units of measure are type annotations that are added to certain existing types. Such annotations are used to ensure that we do not mix values that, even though hey have the same type, have incompatible meanings.

    It is well known that two floating point numbers, such as 3.0 and 9.8 can be added, resulting in 12.8.
    It is also well known that if those numbers represent, respectively, meters and meters per seconds squared then they should not be added because the result would have no meaning.

    We can define certain types so that they represent units of measure in F# with the [<Measure>] attribute. Types that represent units of measure can either be elementary or composite:
    *)

    [<Measure>]
    type m

    [<Measure>]
    type kg

    [<Measure>]
    type s

    [<Measure>]
    type N = kg * m / s^2

    (*
    A value may now be marked as having a certain unit of measure by adding a type annotation on its declaration or its value:
    *)

    let g = 9.81<m/s^2>
    let m:int<m> = 3<m>
    let x = 3.0<m>

    (*
    If we wrote
    x + g

    then the compiler would give us an error.
    *)

    (*
    We can define conversion operations, such as conversions from meters to kilometers and backwards:
    *)

    [<Measure>]
    type km

    let m_to_km (v:float<m>) = v * 1000.0<km / m>
    let km_to_m (v:float<km>) = v / 1000.0<km / m>

    (*
    Units of measure can be used to annotate records or other custom types.
    We declare our record with a type parameter marked with the [<Measure>] attribute:
    *)

    type Vector2< [<Measure>] 'a > = { X : float<'a>; Y : float<'a> }

    let v1 = { X = 1.0<m>; Y = 1.0<m> }
    let v2 = { X = 1.0<m/s>; Y = 1.0<m/s> }

    (*
    Given the above definitions, we are prevented from adding v1 and v2 thanks to a compiler error.
    Also, if we write:
    *)

    let v3 = { X = v1.X / v2.X; Y = v1.Y / v2.Y }

    (*
    Then F# type inference will give v3 the type Vector2<s>, which is exactly what we expected.
    Moreover, we are prevented from making mistakes such as writing
    { X = v1.X / v2.X; Y = v2.Y / v1.Y }

    because the units of measure of X and Y must be the same.
    *)

    (*
    Units of Measure as Contracts ( ** )

    Units of measure are more than just a way to simplify the life of programming physicists and game developers.
    Units of measure cna act as a way to annotate essentially any value with additional information without having to define another type.

    Consider the case where we wish to make sure that unsecure channels do not get confidential information.
    We start by defining units of measure for discriminating confidential and public data, and also secure and unsecure channels
    *)

    [<Measure>]
    type confidential

    [<Measure>]
    type public_domain

    [<Measure>]
    type secure

    [<Measure>]
    type unsecure

    (*
    We can now define channels and communications with a unit of measure that defines how secure or confidential they are, and we can define a function for sending messages that essentially forbids the combination of sending a confidential message on an unsecure channel.
    *)

    type Channel< [<Measure>] 's > = { Stream : System.IO.Stream }

    type Communication< [<Measure>] 'd > = { Message : string }

    let send_confidential_message (c:Channel<secure>, m:Communication<confidential>) = failwith "not implemented"
    let send_public_message (c:Channel<'a>, m:Communication<public_domain>) = failwith "not implemented"



